/*
Copyright (C) 2011 The University of Michigan

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Please send inquiries to powertutor@umich.edu
 */

package vn.cybersoft.obs.andriod.batterystats2.util;

import android.os.SystemClock;

public class Counter {
	public static final int WINDOW_MINUTE = 0;
	public static final int WINDOW_HOUR = 1;
	public static final int WINDOW_DAY = 2;
	public static final int WINDOW_TOTAL = 3;
	public static final CharSequence[] WINDOW_NAMES = { "Last minute",
		"Last Hour", "Last Day", "Total" };
	// To be used for constructions like "Showing X over ..."
	public static final CharSequence[] WINDOW_DESCS = { "the last minute",
		"the last hour", "the last day", "all time" };
	private static final long WINDOW_DURATIONS[] = { 60 * 1000, 60 * 60 * 1000,
		24 * 60 * 60 * 1000 };

	private long startTime;
	private long total;
	private SingleCounter[] counters;

	public Counter() {
		total = 0;
		startTime = SystemClock.elapsedRealtime();
		counters = new SingleCounter[WINDOW_DURATIONS.length];
		for (int i = 0; i < counters.length; i++) {
			counters[i] = new SingleCounter();
		}
	}

	public void add(long x) {
		total += x;
		long now = SystemClock.elapsedRealtime() - startTime;
		for (int i = 0; i < counters.length; i++) {
			counters[i].add(x, now * SingleCounter.BUCKETS
					/ WINDOW_DURATIONS[i]);
		}
	}

	public long get(int window) {
		if (window == WINDOW_TOTAL) {
			return total;
		}
		long now = SystemClock.elapsedRealtime() - startTime;
		return counters[window].get(now * SingleCounter.BUCKETS
				/ WINDOW_DURATIONS[window],
				(1.0 * now * SingleCounter.BUCKETS % WINDOW_DURATIONS[window])
				/ WINDOW_DURATIONS[window]);
	}

	private static class SingleCounter {
		public static final int BUCKETS = 60;

		private long base;
		private int baseIdx;
		private long droppingBucket;
		private long[] bucketSum;
		private long total;

		public SingleCounter() {
			bucketSum = new long[BUCKETS];
		}

		private void wind(long now) {
			if (base + 2 * BUCKETS <= now) {
				/* Completly clear the data structure. */
				droppingBucket = 0;
				for (int i = 0; i < BUCKETS; i++) {
					bucketSum[i] = 0;
				}
				total = 0;
				base = now;
				baseIdx = 0;
			} else
				while (base + BUCKETS <= now) {
					droppingBucket = bucketSum[baseIdx];
					total -= droppingBucket;
					bucketSum[baseIdx] = 0;
					base++;
					baseIdx = baseIdx + 1 == BUCKETS ? 0 : baseIdx + 1;
				}
		}

		public void add(long x, long now) {
			wind(now);
			total += x;
			int idx = (int) (baseIdx + now - base);
			bucketSum[idx < BUCKETS ? idx : idx - BUCKETS] += x;
		}

		/*
		 * now gives the time slice that we want information for. prog, between
		 * 0 and 1, gives the progress through the current time slice with 0
		 * indicating that it just started and 1 indicating that it is about to
		 * end.
		 */
		public long get(long now, double prog) {
			wind(now);
			return total + (long) ((1.0 - prog) * droppingBucket);
		}
	}
}
